﻿(function (glob) {
    AugmentedReality.SCREEN_WIDTH = 800;
    AugmentedReality.SCREEN_HEIGHT = 600;
    AugmentedReality.MAX_AR_ELEMENTS = 7;
    AugmentedReality.DURATION = 1000;
    AugmentedReality.KEYFRAMES = 14;
    AugmentedReality.INTERPOLATION = AugmentedReality.DURATION / AugmentedReality.KEYFRAMES;
    AugmentedReality.THRESHOLD = 128;

    // set the value for the default rotation for the desired object
    AugmentedReality.DEFAULTROTATION = 15.8;

    function AugmentedReality(cont) {
        //this.core = null;
        this.isRunning = false;
        this.container = cont;
        this.ARElement = 1;
        this.lastKeyframe = 0;
        this.currentKeyframe = 0;
        __createWebGLRenderer.call(this);
        __createScene.call(this);
        __createCamera.call(this);
        __createWebCamVideo.call(this);
        window.addEventListener("keydown", doKeyDown);
        var url = window.URL || window.webkitURL;
        var createObjectURL = url.createObjectURL || url.createObjectURL;
        if (!createObjectURL) throw new Error("URL.createObjectURL not found.");

        __getUserMedia.call(this,
			function (stream) {
			    this.video.src = createObjectURL(stream);
			},
			function (error) {
			    alert("Couldn't access webcam.");
			}
		);

        __createVideo3D.call(this);

        glob.addEventListener("load", __createJSARToolkit.bind(this));
    }

    AugmentedReality.prototype.changeModel = function () {
        this.mesh = null;
        this.ARElement++;
        if (this.ARElement > AugmentedReality.MAX_AR_ELEMENTS) this.ARElement = 1;
        return this.ARElement;
    };

    AugmentedReality.prototype.goFullscreen = function () {
        var elem = document.getElementsByTagName("canvas")[0];
        elem.mozRequestFullScreen();
    };

    /**
	 * Create webgl renderer
	 */
    function __createWebGLRenderer() {
        this.renderer = new THREE.WebGLRenderer({ antialias: true });
        this.renderer.setSize(AugmentedReality.SCREEN_WIDTH, AugmentedReality.SCREEN_HEIGHT);
        this.container.appendChild(this.renderer.domElement);
    }

    /**
	 * Create scene
	 */
    function __createScene() {
        this.scene = new THREE.Scene();
    }

    /**
	 * Create camera
	 */
    function __createCamera() {
        // this renders the camera directly above the object
        this.camera = new THREE.PerspectiveCamera(35, this.renderer.domElement.width / this.renderer.domElement.height, 1, 10000);
        this.camera.position.set(0, 0, 0);
        this.scene.add(this.camera);
    }

    /**
	 * Create the video element for the webcam
	 */
    function __createWebCamVideo() {
        this.video = document.createElement("video");
        this.video.width = 320;
        this.video.height = 240;
        this.video.loop = true;
        this.video.volume = 0;
        this.video.autoplay = true;
    }

    function __getUserMedia(onsuccess, onerror) {
        onsuccess = onsuccess.bind(this);
        onerror = onerror.bind(this);
        if (navigator.getUserMedia) {
            return navigator.getUserMedia({ video: true, audio: false }, onsuccess, onerror);
        }
        else if (navigator.webkitGetUserMedia) {
            return navigator.webkitGetUserMedia({ video: true, audio: false }, onsuccess, onerror);
        }
        else if (navigator.mozGetUserMedia) {
            return navigator.mozGetUserMedia({ video: true, audio: false }, onsuccess, onerror);
        }
        else if (navigator.msGetUserMedia) {
            return navigator.msGetUserMedia({ video: true, audio: false }, onsuccess, onerror);
        }
        else {
            onerror(new Error("No getUserMedia implementation found."));
        }
    }

    function __createVideo3D() {
        this.videoTexture = new THREE.Texture(this.video);
        var geometry = new THREE.PlaneGeometry(2, 2, 0);
        var material = new THREE.MeshBasicMaterial({
            /*color: 0x6666FF,*/
            map: this.videoTexture,
            depthTest: false,
            depthWrite: false
        });
        var plane = new THREE.Mesh(geometry, material);
        this.videoScene = new THREE.Scene();
        this.videoCamera = new THREE.Camera();
        this.videoScene.add(plane);
        this.videoScene.add(this.videoCamera);
    }

    function __createJSARToolkit() {
        this.markers = {};

        this.threexAR = new THREEx.JSARToolKit({
            srcElement: this.video,
            threshold: AugmentedReality.THRESHOLD,
            //canvasRasterW	: 640,
            //canvasRasterH	: 480,
            //debug: false,
            camera: this.camera,
            callback: function (e) {
                //console.log("event", e.type, e.markerId)
                if (e.type === "create") {
                    __onCreate.call(this, e);
                }
                else if (e.type === "delete") {
                    __onDelete.call(this, e);
                }
                else if (e.type === "update") {
                    __onUpdate.call(this, e);
                }
                else {
                    console.assert(false, "invalid event type " + e.type);
                }
            }.bind(this)
        });

        this.threexAR.canvasRaster().id = "canvasRaster";

        __animate.call(this);
    }

    function __onCreate(e) {
        var markerId = e.markerId;
        this.markers[markerId] = {};
        var marker = this.markers[markerId];
        marker.object3d = new THREE.Object3D();
        marker.object3d.matrixAutoUpdate = false;
        this.scene.add(marker.object3d);

        // adding ambient light to the scene
        var light = new THREE.PointLight(0xffffff);
        light.position.set(-100, 150, 100);

        // need to add an ambient light
        // for ambient colors to be visible
        // make the ambient light darker so that
        // it doesn't overwhelm (like emmisive light)
        var light2 = new THREE.AmbientLight(0x404040);
        light2.position.set(light.position);
        this.scene.add(light2);
        var lightbulbGeometry = new THREE.SphereGeometry(10, 16, 8);
        var lightbulbMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.8, blending: THREE.AdditiveBlending });
        var wireMaterial = new THREE.MeshBasicMaterial({ color: 0x000000, wireframe: false });
        var materialArray = [lightbulbMaterial, wireMaterial];
        var lightbulb = THREE.SceneUtils.createMultiMaterialObject(lightbulbGeometry, materialArray);
        lightbulb.position = light.position;
        //scene.add(lightbulb);
        marker.object3d.add(light);

        // FLOOR
        var floorTexture = new THREE.ImageUtils.loadTexture('images/wood.jpg');
        floorTexture.wrapS = floorTexture.wrapT = THREE.RepeatWrapping;
        floorTexture.repeat.set(10, 10);
        var floorMaterial = new THREE.MeshBasicMaterial({ map: floorTexture, side: THREE.DoubleSide });
        var floorGeometry = new THREE.PlaneGeometry(1000, 1000, 10, 10);
        this.floor = new THREE.Mesh(floorGeometry, floorMaterial);
        this.floor.position.y = 0;// -100;
        this.floor.rotation.x = 0;// Math.PI / 2;
        // marker.object3d.add(this.floor);

        var currentObject;
        var texture, loader, material;
        
        // adding a new model to the scene
        if (this.core === null || this.core === undefined || (((this.core === undefined || this.core === null)&& this.isRunning === true))) {
            var objArr = __loadObject(marker, this);// loadCollada(marker, this);
            console.log(objArr[0]);
            this.core = objArr[0];
            this.isRunning = objArr[1];
        }
        else {
            marker.object3d.add(this.core);
        }
    }

    function __loadObject(marker, objT) {
        var currentObjectArray = [];
        var loader = new THREE.OBJMTLLoader();
        var hasLoaded = false;
        //loader.options.convertUpAxis = true;
        loader.addEventListener('load', function (event) {
            var currentObject = event.content;
            //debugger;
            currentObject.matrixWorld = marker.object3d.matrixWorld;
            currentObject.position = marker.object3d.position;
            currentObject.rotation.y = 0;
            currentObject.rotation.x = AugmentedReality.DEFAULTROTATION;
            currentObject.rotation.z = 0;
            s = 3;
            currentObject.scale.set(s, s, s);
            currentObjectArray.push(currentObject);
            currentObjectArray.push(true);
            //console.log(objT);
            objT.core = currentObject;
            var meshCount = 0;
            marker.object3d.add(currentObject);
            hasLoaded = true;
            update(currentObject.scale.x);
        });

        loader.load('object/visuallize/ExportedModel.obj', 'object/visuallize/ExportedModel.mtl');
        currentObjectArrayT(hasLoaded);
        console.log("The current object array" + currentObjectArray);
         
        var sliderValue = $("#scaleChange").data("kendoSlider");
        sliderValue.value(this.augmentedReality.core.scale.x * 10);
        return currentObjectArray;
    }

    function loadCollada(marker, objT) {
        var currentObjectArray = [];
        var hasLoaded = false;
        var loader = new THREE.ColladaLoader();
       // loader.options.convertUpAxis = true;


        loader.load("object/models/Goetz Sofa from Smart Furniture.dae", function (collada) {
            dae = collada.scene;
            skin = collada.skins[0];

            dae.matrixWorld = marker.object3d.matrixWorld;
            dae.position = marker.object3d.position;
            dae.rotation.y = 0;
            dae.rotation.x = AugmentedReality.DEFAULTROTATION;
            dae.rotation.z = 0;
            dae.scale.x = dae.scale.y = dae.scale.z = 1;
            //dae.scale.x = dae.scale.y = dae.scale.z = 0.002;
            dae.updateMatrix();
            currentObjectArray.push(dae);
            currentObjectArray.push(true);
            //console.log(objT);
            objT.core = dae;
            var meshCount = 0;
            //currentObject.traverse(function (child) {

            //  //  debugger;
            //    if (child instanceof THREE.Mesh) {
            //        child.material.color.setHex('0x07c607');
            //       // meshCount++;
            //    }


            //});
            //alert(meshCount);

            //debugger;
            marker.object3d.add(dae);
            hasLoaded = true;

        });

        update(undefined);
        //currentObjectArrayT(hasLoaded);
        //console.log("The current object array" + currentObjectArray);
    }

   

    function __onDelete(e) {
        var markerId = e.markerId;
        var marker = this.markers[markerId];
        this.scene.remove(marker.object3d);
        delete this.markers[markerId];
    }

    function __onUpdate(e) {
        var markerId = e.markerId;
        var marker = this.markers[markerId];
        marker.object3d.matrix.copy(e.matrix);
        marker.object3d.matrixWorldNeedsUpdate = true;
    }
     
    function __animate() {
        requestAnimationFrame(__animate.bind(this));

        if (this.mesh && this.ARElement == 2) {
            var time = Date.now() % AugmentedReality.DURATION;
            var keyframe = Math.floor(time / AugmentedReality.INTERPOLATION);

            if (keyframe != this.currentKeyframe) {
                this.mesh.morphTargetInfluences[this.lastKeyframe] = 0;
                this.mesh.morphTargetInfluences[this.currentKeyframe] = 1;
                this.mesh.morphTargetInfluences[keyframe] = 0;

                this.lastKeyframe = this.currentKeyframe;
                this.currentKeyframe = keyframe;
            }

            this.mesh.morphTargetInfluences[keyframe] = (time % AugmentedReality.INTERPOLATION) / AugmentedReality.INTERPOLATION;
            this.mesh.morphTargetInfluences[this.lastKeyframe] = 1 - this.mesh.morphTargetInfluences[keyframe];
        }

        __render.call(this);
    }

    function __render() {
        if (this.video instanceof HTMLVideoElement && this.video.readyState === this.video.HAVE_ENOUGH_DATA) {
            this.videoTexture.needsUpdate = true;
            this.threexAR.update();
        }

        this.renderer.autoClear = false;
        this.renderer.clear();
        this.renderer.render(this.videoScene, this.videoCamera);
        this.renderer.render(this.scene, this.camera);
    }

    if (typeof define == "function" && define.amd) {
        define(function () {
            return AugmentedReality;
        });
    } else {
        glob.AugmentedReality = AugmentedReality;
    }

    function doKeyDown(e) {
        if (this.keyboard.pressed("z")) {
            console.log("pressed");
            this.augmentedReality.core.scale.x -= .01;
            this.augmentedReality.core.scale.y -= .01;
            this.augmentedReality.core.scale.z -= .01;
        }
        if (this.keyboard.pressed("x")) {
            this.augmentedReality.core.scale.x += .01;
            this.augmentedReality.core.scale.y += .01;
            this.augmentedReality.core.scale.z += .01;
        }
        if (this.keyboard.pressed("c")) {
            this.augmentedReality.core.rotation.z += 1;
           // this.augmentedReality.core.material = 
        }
        if (this.keyboard.pressed("d")) {
            //loadFloorTexture('wood');
        }
    }

    // function to update the scroller
    function update(modelScale) {
        var sliderValue =  $("#scaleChange").data("kendoSlider");
        sliderValue.value(modelScale * 10);

        // check if it is a scale or a rotation then change the worlds accordingly
    }
}(window));

function rotateAroundWorldAxis(object, axis, radians) {
    var rotationMatrix = new THREE.Matrix4();

    rotationMatrix.makeRotationAxis(axis.normalize(), radians);
    rotationMatrix.multiplySelf(object.matrix);                       // pre-multiply
    object.matrix = rotationMatrix;
    object.rotation.setEulerFromRotationMatrix(object.matrix);
}

function currentObjectArrayT(currentObjectArray) {
    if (currentObjectArray === true) {
        return currentObjectArray;
    }
    else {
        window.setTimeout("currentObjectArrayT(" + currentObjectArray + ");", 10);
    }
}